package top.suven.base.http.Interceptor;

import top.suven.base.core.spring.SpringUtil;
import top.suven.base.http.JsonParse;
import top.suven.base.http.config.HttpServiceConfig;
import top.suven.base.http.enums.PlatformEnumType;
import top.suven.base.http.enums.SysMsgEnumType;
import top.suven.base.http.exception.SystemRuntimeException;
import top.suven.base.http.handler.OutputMessage;
import top.suven.base.http.message.ParamMessage;
import top.suven.base.http.message.ParamMessageConstant;
import top.suven.base.http.message.RequestMessage;
import top.suven.base.http.message.RequestRemote;
import top.suven.base.http.processor.url.UrlExplain;
import top.suven.base.util.constants.Constants;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.NoHandlerFoundException;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;


import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.Map;

/**
 * @ClassName:
 * @Description:
 * @Author lixiangling
 * @Date 2018/5/21 18:48
 * @Copyright: (c) 2018 gc by https://www.gc.com.cn/
 * @Version : 1.0.0
 * --------------------------------------------------------
 * modifyer    modifyTime                 comment
 * <p>
 * --------------------------------------------------------
 */
@Component("paramerHandlerInterceptor")
public class ParamerHandlerInterceptor extends HandlerInterceptorAdapter {
    private Logger logger = LoggerFactory.getLogger(ParamerHandlerInterceptor.class);

    private final String SERVER_ERROR_URL = Constants.SERVER_ERROR_URL;
//    @Value("${gc.isCheckParamSign:false}")
    private boolean isCheckParamSign;
    public ParamerHandlerInterceptor(){
    }
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
       if(true){
           return true;
       }
        RequestRemote remote = ParamMessage.getRequestRemote();
        RequestMessage message = ParamMessage.getRequestMessage();
        if(remote == null){
            logger.warn(" TokenHandlerInterceptor RequestRemote is null remote: [{}] ", remote );
            return false;
        }
        if(SERVER_ERROR_URL.equals(remote.getUrl())){
            throw new NoHandlerFoundException("paramerpreHandle",request.getRequestURI(),new HttpHeaders());
        }
        HttpServiceConfig httpServiceConfig = SpringUtil.getBean(HttpServiceConfig.class);
        isCheckParamSign = httpServiceConfig.isCheckParamSign();
        this.checkRequestParam(message);//基本请求参数验证
        if(remote.isPostReq()){ //post或get 基础参数验证;
            checkPostParam(message,remote);
        }else{
            checkGetParam(message);
        }
        //具体业务参数验证;
        this.checkOnlyParameter((HandlerMethod) handler, request);
        return true;
    }

    /**
     * @Title: 公共参数校验
     * @Description:
     * @param
     * @return
     * @throw
     * @author lixiangling
     * @date 2018/5/28 14:06
     *  --------------------------------------------------------
     *  modifyer    modifyTime                 comment
     *
     *  --------------------------------------------------------
     */
    private void checkRequestParam(RequestMessage message)throws SystemRuntimeException {
        SysMsgEnumType sysMsgEnumType =  SysMsgEnumType.SYS_PARAM_ERROR;
        if(message.getClientId()<=0){
            throw new SystemRuntimeException(sysMsgEnumType, ParamMessageConstant.System.CLIENT_IS_NOT_NULL);
        }else if(null == PlatformEnumType.valueOf(message.getPlatform())){
            logger.warn("非法请求platform={}",message.getPlatform());
            throw new SystemRuntimeException(SysMsgEnumType.SYS_INVALID_REQUEST);
        }
//        else if(message.getVersion() == 0){
//            logger.warn("非法请求version={}",message.getVersion());
//            throw new SystemRuntimeException(SysMsgEnumType.SYS_INVALID_REQUEST);
//        }
        else if(message.getVtoInt() == 0){
            logger.warn("非法请求V={}",message.getV());
            throw new SystemRuntimeException(SysMsgEnumType.SYS_INVALID_REQUEST);
        }

    }
    /**
     * @Title: GET请求参数校验
     * @Description:
     * @param
     * @return
     * @throw
     * @author lixiangling
     * @date 2018/5/28 14:06
     *  --------------------------------------------------------
     *  modifyer    modifyTime                 comment
     *
     *  --------------------------------------------------------
     */
    private void checkGetParam(RequestMessage message){

    }
    /**
     * @Title: POST请求参数校验
     * @Description:
     * @param
     * @return
     * @throw
     * @author lixiangling
     * @date 2018/5/28 14:06
     *  --------------------------------------------------------
     *  modifyer    modifyTime                 comment
     *
     *  --------------------------------------------------------
     */
    private void checkPostParam(RequestMessage message,RequestRemote remote)throws SystemRuntimeException{
        SysMsgEnumType sysMsgEnumType =  SysMsgEnumType.SYS_PARAM_ERROR;
//        if(StringUtils.isBlank(message.getCuid())){//||!message.getCuid().matches("^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{1,64}$")
//            logger.warn("非法请求cuid={}",message.getCuid());
//            throw new SystemRuntimeException(SysMsgEnumType.SYS_CUID_FORMAT_ERROR);
//        }else
        if(!remote.isWhite()){
            if(message.getUserId() <= 0 || StringUtils.isBlank(message.getAccessToken()) || StringUtils.isBlank(message.getSessionId())){
                logger.warn("login faild userId={},accessToken={},sessionId={}",message.getUserId(),message.getAccessToken(),message.getSessionId());
                throw new SystemRuntimeException(SysMsgEnumType.SYS_TOKEN_NULL);
            }
        }

        if(StringUtils.isBlank(message.getSysVersion())){
            throw new SystemRuntimeException(sysMsgEnumType).format( ParamMessageConstant.System.SYS_VERSION_IS_NOT_NULL);
        }else if(StringUtils.isBlank(message.getChannelCode())){
            throw new SystemRuntimeException(sysMsgEnumType).format(ParamMessageConstant.System.CHANNEL_CODE_IS_NOT_NULL);
        }else if(message.getTimes() == 0){
            throw new SystemRuntimeException(sysMsgEnumType).format(ParamMessageConstant.System.TIMES_IS_NOT_NULL);
        }else if((isCheckParamSign || UrlExplain.isParamSign(remote.getUrl())) && !remote.getSrvMd5Sign().equals(remote.getCliMd5Sign())){
            logger.warn("非法请求client_sign={},server_sign={}",remote.getCliMd5Sign(),remote.getSrvMd5Sign());
            throw new SystemRuntimeException(SysMsgEnumType.SYS_INVALID_REQUEST);
        }

    }

    /**
     * 具体实现业务参数验证;
     * @param handlerMethod
     * @param request
     * @throws Exception
     */
    private void checkOnlyParameter(HandlerMethod handlerMethod, HttpServletRequest request)throws Exception{
        Type[] parameterTypes = handlerMethod.getMethod().getGenericParameterTypes();
        if(parameterTypes == null || parameterTypes.length <1){
            return;
        }
        Map paramMap = request.getParameterMap();
        for (Type parameterType : parameterTypes){
            if(parameterType == OutputMessage.class || parameterType == HttpServletRequest.class
                    || parameterType == HttpServletResponse.class || parameterType == HttpSession.class){
                continue;
            }
            Class genericClazz = null;
            if (parameterType instanceof ParameterizedType) {
                ParameterizedType pt = (ParameterizedType) parameterType;
                Type rawType =  pt.getRawType();
                if(rawType == java.util.List.class || rawType == java.util.Set.class || rawType == java.util.Arrays.class
                        || rawType == java.util.Queue.class || rawType == java.util.Iterator.class ){
                    genericClazz = (Class<?>)pt.getActualTypeArguments()[0];
                }else if(rawType == java.util.Map.class){
                    genericClazz = (Class<?>)pt.getActualTypeArguments()[1];
                }else {
                    genericClazz = (Class)rawType;
                }
            } else if (parameterType instanceof TypeVariable) {
                TypeVariable tType = (TypeVariable) parameterType;
                genericClazz = tType.getGenericDeclaration().getClass();
            } else {
                genericClazz = (Class) parameterType;
            }
            if(genericClazz == null){
                return;
            }
            Object json = JsonParse.parseFrom(paramMap, genericClazz);
            if(json instanceof JsonParse) {
                ParamMessage.setJsonParse(json);
            }
        }
    }

}
